package com.pek.annontation.Permit;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.pek.Exception.PermitException;
import com.pek.Exception.TokenException;
import com.pek.control.entity.UserEntity;
import com.pek.control.service.IUserService;
import com.pek.control.util.RedisUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.concurrent.TimeUnit;


/**
 * Permit注解的切面类
 */
@Aspect
@Component
@Slf4j
public class PermitAop {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private IUserService userService;

    /**
     * 切面方法
     */
    @Pointcut("@annotation(Permit)")
    public void permit() {

    }

    /**
     * 前置切面
     */
    @Before("@annotation(Permit)")
    public void before(JoinPoint joinpoint) throws PermitException {
        var sign = joinpoint.getSignature();
        //获取注解
        Permit permit = ((MethodSignature) sign).getMethod().getAnnotation(Permit.class);
        //获取请求头
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        if (StringUtils.isBlank(request.getHeader("TOKEN"))) {
            throw new PermitException();
        }
        String token = request.getHeader("TOKEN");
        //时间拦截
        String redisKey = "FILTER-TIME-"+token+sign.toShortString();
        if(redisUtil.hasKey(redisKey) && permit.time() > 0){
            throw new PermitException(String.format("拒绝访问：%d毫秒内只能请求一次!", permit.time()));
        }else if (permit.time() > 0){
            redisUtil.set(redisKey, true , permit.time() , TimeUnit.MILLISECONDS);
        }
        //获取token中的用户
        JSONObject object = (JSONObject) (redisUtil.get(token));
        String userId = object.getString("id");
        UserEntity user = userService.getById(userId);
        if (null == user) {
            throw new PermitException();
        }
        //判断用户是否是ADMIN 如果是直接放行
        String userPermit = user.getPermit();
        //因为ADMIN用户不需要其他权限 这里为了严谨直接使用eq
        if (userPermit.equalsIgnoreCase(UserPermit.ADMIN.value)) {
            return;
        }
        //权限拦截器
        if ((permit.type() == PermitType.PERMIT || permit.type() == PermitType.ALL) &&
                !userPermit.contains(UserPermit.ALL.value)) {
            //根据用户获取是否有权限
            UserPermit[] values = permit.value();
            for (UserPermit value : values) {
                if (!userPermit.contains(value.value)) {
                    log.info("【权限拦截器】权限不足，{}不含有权限{} | FROM -> {}", user.getUsername(), value.value, sign.toShortString());
                    throw new PermitException("拒绝访问：权限不足");
                }
            }
        }
        //等级拦截器
        if (permit.type() == PermitType.LEVEL || permit.type() == PermitType.ALL) {
            if (permit.level() > user.getLevel()) {
                log.info("【等级拦截器】等级过低，{}的等级{}低于需要的{} | FROM -> {}", user.getUsername(), user.getLevel(), permit.level(), sign.toShortString());
                throw new PermitException("拒绝访问：等级过低");
            }
        }
    }
}
